package reflect02;

import org.junit.Test;
import reflect01.Person;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 反射(解剖出)构造方法
 * Class<T>:T代表字节码对象所表示的类
 * 基本的 Java 类型（boolean、byte、char、short、int、long、float 和 double）和关键字 void 也表示为 Class 对象。
 * 只需要将基本类型后面带上.class就表示Class的实例
 * Class类中成员方法:
 *   Constructor<T> getConstructor(Class<?>... parameterTypes)
 *           返回一个 Constructor 对象，它反映此 Class 对象所表示的类的指定公有(public)构造方法。
 *           <T>:表示当前字节码对象代表的类
 *
 *   Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
 *           获取类中声明的任意一个构造方法
 *
 *    T newInstance()
 *           只能利用该类的空参构造创建对象,不能利用有参构造创建对象
 *
 * Constructor类中的方法
 *   String getName()
 *           以字符串形式返回此构造方法的名称。
 *   T newInstance(Object... initargs)
 *           使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例，并用指定的初始化参数初始化该实例
 */
public class ReflectDemo01 {
	@Test
	public void testMethod01() throws Exception{
	  //1.获取字节码对象
		Class<Person> pCls = Person.class;

	  //2.获取构造方法
		Constructor<Person> cons = pCls.getConstructor();//由于获取的时候空参构造,所以不需要传递任何参数,因此使用getConstructor()方法也不需要传递参数

		//3.获取构造方法的信息
		System.out.println(cons.getName());//获取构造方法的名称 reflect01.Person

		//4.利用构造方法创建对象
		Person p = cons.newInstance();//利用空参构造创建对象
                                      //类比:Person p=new Person();
		System.out.println(p);//reflect01.Person@5e8c92f4
	}

	@Test
	public void testMethod02() throws Exception {
		//1.获取字节码对象
		Class<Person> pCls = Person.class;
		//2.直接利用Class类的newInstance()方法创建该类实例
		Person p = pCls.newInstance();//底层相当于:Person p=new Person();
		System.out.println(p);//reflect01.Person@5e8c92f4
	}

	@Test
	public void testMethod03() throws Exception {
		//1.获取字节码对象并获取有参构造
		Constructor<Person> cons = Person.class.getConstructor(String.class, int.class);//获取指定形参为String,int类型的构造方法

		//2.利用这个有参构造创建对象
		Person p = cons.newInstance("老王", 30);//类比:Person p=new Person("老王",30)
		System.out.println(p);
	}

	/**
	 * 暴力反射:获取类中私有属性
	 * @throws Exception
	 */
	@Test
	public void testMethod04() throws Exception {
		 //1.获取字节码对象
		Class<Person> pCls = Person.class;

		//2.获取构造方法
		//Constructor<Person> cons = pCls.getConstructor(String.class);
		Constructor<Person> cons = pCls.getDeclaredConstructor(String.class);

		//3.由于是将要利用私有构造方法创建对象,在类外无法调用私有构造方法,但是我们可以让java取消权限检查
		cons.setAccessible(true);

		//4.利用该构造方法创建对象
		Person p = cons.newInstance("老李");//类似:Person p=new Person("老李")
		System.out.println(p);
	}
}
